package com.snapan.es.service.Impl;

import com.snapan.entity.FileHistory;
import com.snapan.es.entity.FileShareDocument;
import com.snapan.es.entity.UserFileDocument;
import com.snapan.es.service.EsSearchService;
import com.snapan.service.FileHistoryService;
import org.apache.http.entity.FileEntity;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public  class EsSearchServiceImpl implements EsSearchService {
    @Autowired
    private ElasticsearchRestTemplate esTemplate;
    @Autowired
    private FileHistoryService fileHistoryService;

    // 在 EsSearchServiceImpl 类中添加映射常量
    private static final Map<String, List<String>> FILE_TYPE_SUFFIX_MAP = new HashMap<>();
    static {
        // 图片类型后缀
        FILE_TYPE_SUFFIX_MAP.put("image",
                Arrays.asList(".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".svg"));
        // 文档类型后缀
        FILE_TYPE_SUFFIX_MAP.put("document",
                Arrays.asList(".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt", ".md", ".rtf"));
        // 视频类型后缀
        FILE_TYPE_SUFFIX_MAP.put("video",
                Arrays.asList(".mp4", ".avi", ".mov", ".wmv", ".flv", ".mkv", ".webm"));
        // 音频类型后缀
        FILE_TYPE_SUFFIX_MAP.put("audio",
                Arrays.asList(".mp3", ".wav", ".aac", ".flac", ".ogg", ".m4a"));
        // 其他类型（无匹配后缀时）
        FILE_TYPE_SUFFIX_MAP.put("other", new ArrayList<>());
    }

    @Override
    public List<Map<String, Object>> multiConditionSearch(Long userId, FileHistory history) {


        // 1. 构建布尔查询（所有条件可选填，默认查有效文件）
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("userId", userId)) // 必选：用户隔离
                .must(QueryBuilders.termQuery("isDirectory", false)); // 必选：默认搜索文件

        // 可选条件1：关键词搜索（保留英文子字段，添加minimum_should_match）
        if (history.getKeyword() != null && !history.getKeyword().trim().isEmpty()) {
            String keyword = history.getKeyword().trim();

            // 核心：如果关键词以 . 开头，自动去掉 .（如 .txt → txt）
            if (keyword.startsWith(".")) {
                keyword = keyword.substring(1);
            }

            // 构建查询：同时匹配拆分后的词条和整体词条
            boolQuery.should(QueryBuilders.matchQuery("fileName", keyword))  // 利用 IK 分词匹配（支持中文整体）
                    .should(QueryBuilders.wildcardQuery("fileName", "*" + keyword + "*"))  // 通配符匹配（兼容特殊场景）
                    .should(QueryBuilders.wildcardQuery("realName", "*" + keyword + "*"))
                    .should(QueryBuilders.matchQuery("fileContent", keyword))
                    .should(QueryBuilders.wildcardQuery("fileName.en", "*" + keyword + "*"))
                    .should(QueryBuilders.wildcardQuery("realName.en", "*" + keyword + "*"))
                    .should(QueryBuilders.wildcardQuery("fileContent.en", "*" + keyword + "*"))
                    .minimumShouldMatch(1);  // 至少匹配一个条件
        }

        // 可选条件2：用户自定义文件名筛选（精确模糊匹配）
        if (history.getFileName() != null && !history.getFileName().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.wildcardQuery("fileName", "*" + history.getFileName() + "*"));
        }

        // 可选条件3：文件类型筛选（根据类型匹配对应后缀列表）
        if (history.getFileType() != null && !history.getFileType().trim().isEmpty()) {
            String fileType = history.getFileType().trim();
            List<String> suffixList = FILE_TYPE_SUFFIX_MAP.get(fileType);

            if (suffixList != null && !suffixList.isEmpty()) {
                // 若有后缀列表，匹配 fileSuffix 属于该列表
                boolQuery.filter(QueryBuilders.termsQuery("fileSuffix", suffixList));
            } else if ("other".equals(fileType)) {
                // 若为“其他”类型，匹配 fileSuffix 不属于所有已知后缀
                List<String> allKnownSuffixes = new ArrayList<>();
                FILE_TYPE_SUFFIX_MAP.forEach((type, suffixes) -> allKnownSuffixes.addAll(suffixes));
                boolQuery.filter(QueryBuilders.boolQuery()
                        .mustNot(QueryBuilders.termsQuery("fileSuffix", allKnownSuffixes))
                        .should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("fileSuffix")))
                        .minimumShouldMatch(1));
            }
        }

        // 可选条件4：文件大小范围筛选
        if (history.getMinSize() != null || history.getMaxSize() != null) {
            BoolQueryBuilder sizeQuery = QueryBuilders.boolQuery();
            if (history.getMinSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").gte(history.getMinSize()));
            }
            if (history.getMaxSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").lte(history.getMaxSize()));
            }
            boolQuery.filter(sizeQuery);
        }

        // 可选条件5：时间范围筛选（修复时间格式，用时间戳查询）
        String timeField = "userFileUpdateTime"; // 默认时间字段
        if (history.getSortField() != null && "fileBaseUpdateTime".equals(history.getSortField())) {
            timeField = "fileBaseUpdateTime";
        }
        if (history.getStartTime() != null || history.getEndTime() != null) {
            BoolQueryBuilder timeQuery = QueryBuilders.boolQuery();
            if (history.getStartTime() != null) {
                // 直接传入时间戳（毫秒），无需格式化
                timeQuery.must(QueryBuilders.rangeQuery(timeField).gte(history.getStartTime().getTime()));
            }
            if (history.getEndTime() != null) {
                timeQuery.must(QueryBuilders.rangeQuery(timeField).lte(history.getEndTime().getTime()));
            }
            boolQuery.filter(timeQuery);
        }

        // 可选条件6：是否目录筛选（0-文件，1-目录，未选则默认文件）
        if (history.getIsDirectory() != null) {
            boolQuery.filter(QueryBuilders.termQuery("isDirectory", history.getIsDirectory() == 1));
        }

        // 可选条件7：真实名筛选（精确模糊匹配）
        if (history.getRealName() != null && !history.getRealName().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.wildcardQuery("realName", "*" + history.getRealName() + "*"));
        }

        // 2. 构建高亮配置（包含英文子字段）
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                // 文件名：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("fileName")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .field(new HighlightBuilder.Field("fileName.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                // 真实名：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("realName")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .field(new HighlightBuilder.Field("realName.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                // 文件内容：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("fileContent")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(200))
                .field(new HighlightBuilder.Field("fileContent.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(200))
                .requireFieldMatch(false); // 允许跨字段高亮

        // 3. 构建排序（默认按用户关联时间降序）
        String sortField = history.getSortField() == null ? "userFileUpdateTime" : history.getSortField();
        SortOrder sortOrder = "ASC".equalsIgnoreCase(history.getSortOrder()) ? SortOrder.ASC : SortOrder.DESC;
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withHighlightBuilder(highlightBuilder)
                .withSort(SortBuilders.fieldSort(sortField).order(sortOrder))
                .build();

        // 4. 执行查询并处理结果
        SearchHits<UserFileDocument> searchHits = esTemplate.search(searchQuery, UserFileDocument.class);
        List<Map<String, Object>> resultList = new ArrayList<>();
        searchHits.forEach(hit -> {
            UserFileDocument doc = hit.getContent();
            Map<String, Object> resultMap = new HashMap<>();
            // 基础信息

            resultMap.put("id", doc.getId());
            resultMap.put("filePath", doc.getFilePath());
            resultMap.put("isDirectory", doc.getDirectory());
            resultMap.put("fileName", doc.getFileName());
            resultMap.put("realName", doc.getRealName());
            resultMap.put("fileSize", formatFileSize(doc.getFileSize()));
            resultMap.put("fileType", doc.getFileSuffix());
            resultMap.put("fileSuffix", doc.getFileSuffix());
            resultMap.put("updateTime", doc.getUserFileUpdateTime());
            // 高亮信息（优先子字段，再主字段）
            resultMap.put("highlightFileName", getHighlight(hit, "fileName", doc.getFileName()));
            resultMap.put("highlightRealName", getHighlight(hit, "realName", doc.getRealName()));
            resultMap.put("highlightContent", getHighlight(hit, "fileContent", doc.getFileContent()));
            resultList.add(resultMap);
        });



        return resultList;
    }

    /**
     * 工具：获取高亮内容（优先英文子字段，再主字段）
     */
    private String getHighlight(SearchHit<UserFileDocument> hit, String field, String defaultVal) {
        if (defaultVal == null) {
            return "";
        }
        Map<String, List<String>> highlightFields = hit.getHighlightFields();
        // 先查英文子字段（如fileName.en）
        String enField = field + ".en";
        if (highlightFields.containsKey(enField) && !highlightFields.get(enField).isEmpty()) {
            return highlightFields.get(enField).get(0);
        }
        // 再查主字段（如fileName）
        if (highlightFields.containsKey(field) && !highlightFields.get(field).isEmpty()) {
            return highlightFields.get(field).get(0);
        }
        // 无高亮则返回原始内容（超长截取）
        return defaultVal.length() > 200 ? defaultVal.substring(0, 200) : defaultVal;
    }

    private String getHighlight2(SearchHit<FileShareDocument> hit, String field, String defaultVal) {
        if (defaultVal == null) {
            return "";
        }
        Map<String, List<String>> highlightFields = hit.getHighlightFields();
        // 先查英文子字段（如fileName.en）
        String enField = field + ".en";
        if (highlightFields.containsKey(enField) && !highlightFields.get(enField).isEmpty()) {
            return highlightFields.get(enField).get(0);
        }
        // 再查主字段（如fileName）
        if (highlightFields.containsKey(field) && !highlightFields.get(field).isEmpty()) {
            return highlightFields.get(field).get(0);
        }
        // 无高亮则返回原始内容（超长截取）
        return defaultVal.length() > 200 ? defaultVal.substring(0, 200) : defaultVal;
    }

    /**
     * 工具：格式化文件大小
     */
    private String formatFileSize(Long fileSize) {
        if (fileSize == null) return "0B";
        if (fileSize < 1024) return fileSize + "B";
        if (fileSize < 1024 * 1024) return String.format("%.1fKB", fileSize / 1024.0);
        return String.format("%.1fMB", fileSize / (1024.0 * 1024.0));
    }

    @Override
    public List<Map<String, Object>> getMatchContent(Long userId,FileHistory history) {
        // 1. 构建布尔查询（所有条件可选填，默认查有效文件）
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("userId", userId)) // 必选：用户隔离
                .must(QueryBuilders.termQuery("isDirectory", false)); // 必选：默认搜索文件

        // 可选条件1：关键词搜索（保留英文子字段，添加minimum_should_match）
        if (history.getKeyword() != null && !history.getKeyword().trim().isEmpty()) {
            String keyword = history.getKeyword().trim();

            // 核心：如果关键词以 . 开头，自动去掉 .（如 .txt → txt）
            if (keyword.startsWith(".")) {
                keyword = keyword.substring(1);
            }

            // 构建查询：同时匹配拆分后的词条和整体词条
            boolQuery.should(QueryBuilders.matchQuery("fileName", keyword))  // 利用 IK 分词匹配（支持中文整体）
                    .should(QueryBuilders.wildcardQuery("fileName", "*" + keyword + "*"))  // 通配符匹配（兼容特殊场景）
                    .should(QueryBuilders.wildcardQuery("realName", "*" + keyword + "*"))
                    .should(QueryBuilders.matchQuery("fileContent", keyword))
                    .should(QueryBuilders.wildcardQuery("fileName.en", "*" + keyword + "*"))
                    .should(QueryBuilders.wildcardQuery("realName.en", "*" + keyword + "*"))
                    .should(QueryBuilders.wildcardQuery("fileContent.en", "*" + keyword + "*"))
                    .minimumShouldMatch(1);  // 至少匹配一个条件
        }

        // 可选条件2：用户自定义文件名筛选（精确模糊匹配）
        if (history.getFileName() != null && !history.getFileName().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.wildcardQuery("fileName", "*" + history.getFileName() + "*"));
        }

        // 可选条件3：文件类型筛选（精确匹配 MIME 类型）
        if (history.getFileType() != null && !history.getFileType().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.termQuery("fileSuffix", history.getFileType()));
        }

        // 可选条件4：文件大小范围筛选
        if (history.getMinSize() != null || history.getMaxSize() != null) {
            BoolQueryBuilder sizeQuery = QueryBuilders.boolQuery();
            if (history.getMinSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").gte(history.getMinSize()));
            }
            if (history.getMaxSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").lte(history.getMaxSize()));
            }
            boolQuery.filter(sizeQuery);
        }

        // 可选条件5：时间范围筛选（修复时间格式，用时间戳查询）
        String timeField = "userFileUpdateTime"; // 默认时间字段
        if (history.getSortField() != null && "fileBaseUpdateTime".equals(history.getSortField())) {
            timeField = "fileBaseUpdateTime";
        }
        if (history.getStartTime() != null || history.getEndTime() != null) {
            BoolQueryBuilder timeQuery = QueryBuilders.boolQuery();
            if (history.getStartTime() != null) {
                // 直接传入时间戳（毫秒），无需格式化
                timeQuery.must(QueryBuilders.rangeQuery(timeField).gte(history.getStartTime().getTime()));
            }
            if (history.getEndTime() != null) {
                timeQuery.must(QueryBuilders.rangeQuery(timeField).lte(history.getEndTime().getTime()));
            }
            boolQuery.filter(timeQuery);
        }

        // 可选条件6：是否目录筛选（0-文件，1-目录，未选则默认文件）
        if (history.getIsDirectory() != null) {
            boolQuery.filter(QueryBuilders.termQuery("isDirectory", history.getIsDirectory() == 1));
        }

        // 可选条件7：真实名筛选（精确模糊匹配）
        if (history.getRealName() != null && !history.getRealName().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.wildcardQuery("realName", "*" + history.getRealName() + "*"));
        }

        // 2. 构建高亮配置（包含英文子字段）
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                // 文件名：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("fileName")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .field(new HighlightBuilder.Field("fileName.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                // 真实名：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("realName")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .field(new HighlightBuilder.Field("realName.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                // 文件内容：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("fileContent")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(200))
                .field(new HighlightBuilder.Field("fileContent.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(200))
                .requireFieldMatch(false); // 允许跨字段高亮

        // 3. 构建排序（默认按用户关联时间降序）
        String sortField = history.getSortField() == null ? "userFileUpdateTime" : history.getSortField();
        SortOrder sortOrder = "ASC".equalsIgnoreCase(history.getSortOrder()) ? SortOrder.ASC : SortOrder.DESC;
        Pageable pageable = PageRequest.of(0, 10); // 第0页，每页10条（即最多返回10条）

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQuery) // 设置查询条件
                .withHighlightBuilder(highlightBuilder) // 设置高亮
                .withSort(SortBuilders.fieldSort(sortField).order(sortOrder)) // 设置排序
                .withPageable(pageable) // 用分页限制结果数量（替代size）
                .build();

        // 4. 执行查询并处理结果
        SearchHits<UserFileDocument> searchHits = esTemplate.search(searchQuery, UserFileDocument.class);
        List<Map<String, Object>> resultList = new ArrayList<>();
        searchHits.forEach(hit -> {
            UserFileDocument doc = hit.getContent();
            Map<String, Object> resultMap = new HashMap<>();
            // 仅保留：文件名（优先高亮）、文件内容（优先高亮）
            resultMap.put("fileName", getHighlight(hit, "fileName", doc.getFileName())); // 高亮文件名（前端左侧显示）
            // 截取文件内容前100字符，避免前端面板变形
            String content = getHighlight(hit, "fileContent", doc.getFileContent());
            resultMap.put("fileContent", content.length() > 100 ? content.substring(0, 100) + "..." : content); // 高亮内容（前端右侧显示）

            resultList.add(resultMap);
        });



        return resultList;

    }


    //回收站的全局搜索
    public List<Map<String, Object>> multiConditionRecycleSearch(Long userId, FileHistory history) {


        // 1. 构建布尔查询（所有条件可选填，默认查有效文件）
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("userId", userId)) // 必选：用户隔离
                .must(QueryBuilders.termQuery("isDirectory", false))// 必选：默认搜索文件
                .must(QueryBuilders.termQuery("isRecycled", true))
                .must(QueryBuilders.rangeQuery("userFileExpireTime").gt(new Date()));//过滤过期文件（当前时间 < 过期时间）

        // 可选条件1：关键词搜索（保留英文子字段，添加minimum_should_match）
        if (history.getKeyword() != null && !history.getKeyword().trim().isEmpty()) {
            String keyword = history.getKeyword().trim();

            // 核心：如果关键词以 . 开头，自动去掉 .（如 .txt → txt）
            if (keyword.startsWith(".")) {
                keyword = keyword.substring(1);
            }

            // 构建查询：同时匹配拆分后的词条和整体词条
            boolQuery.should(QueryBuilders.matchQuery("fileName", keyword))  // 利用 IK 分词匹配（支持中文整体）
                    .should(QueryBuilders.wildcardQuery("fileName", "*" + keyword + "*"))  // 通配符匹配（兼容特殊场景）
                    .should(QueryBuilders.wildcardQuery("realName", "*" + keyword + "*"))
                    .should(QueryBuilders.wildcardQuery("fileName.en", "*" + keyword + "*"))
                    .should(QueryBuilders.wildcardQuery("realName.en", "*" + keyword + "*"))
                    .minimumShouldMatch(1);  // 至少匹配一个条件
        }

        // 可选条件2：用户自定义文件名筛选（精确模糊匹配）
        if (history.getFileName() != null && !history.getFileName().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.wildcardQuery("fileName", "*" + history.getFileName() + "*"));
        }

        // 可选条件3：文件类型筛选（根据类型匹配对应后缀列表）
        if (history.getFileType() != null && !history.getFileType().trim().isEmpty()) {
            String fileType = history.getFileType().trim();
            List<String> suffixList = FILE_TYPE_SUFFIX_MAP.get(fileType);

            if (suffixList != null && !suffixList.isEmpty()) {
                // 若有后缀列表，匹配 fileSuffix 属于该列表
                boolQuery.filter(QueryBuilders.termsQuery("fileSuffix", suffixList));
            } else if ("other".equals(fileType)) {
                // 若为“其他”类型，匹配 fileSuffix 不属于所有已知后缀
                List<String> allKnownSuffixes = new ArrayList<>();
                FILE_TYPE_SUFFIX_MAP.forEach((type, suffixes) -> allKnownSuffixes.addAll(suffixes));
                boolQuery.filter(QueryBuilders.boolQuery()
                        .mustNot(QueryBuilders.termsQuery("fileSuffix", allKnownSuffixes))
                        .should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("fileSuffix")))
                        .minimumShouldMatch(1));
            }
        }

        // 可选条件4：文件大小范围筛选
        if (history.getMinSize() != null || history.getMaxSize() != null) {
            BoolQueryBuilder sizeQuery = QueryBuilders.boolQuery();
            if (history.getMinSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").gte(history.getMinSize()));
            }
            if (history.getMaxSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").lte(history.getMaxSize()));
            }
            boolQuery.filter(sizeQuery);
        }

        // 可选条件5：时间范围筛选（修复时间格式，用时间戳查询）
        String timeField = "userFileDeleteTime"; // 默认时间字段
        if (history.getStartTime() != null || history.getEndTime() != null) {
            BoolQueryBuilder timeQuery = QueryBuilders.boolQuery();
            if (history.getStartTime() != null) {
                // 直接传入时间戳（毫秒），无需格式化
                timeQuery.must(QueryBuilders.rangeQuery(timeField).gte(history.getStartTime().getTime()));
            }
            if (history.getEndTime() != null) {
                timeQuery.must(QueryBuilders.rangeQuery(timeField).lte(history.getEndTime().getTime()));
            }
            boolQuery.filter(timeQuery);
        }

        // 可选条件6：是否目录筛选（0-文件，1-目录，未选则默认文件）
        if (history.getIsDirectory() != null) {
            boolQuery.filter(QueryBuilders.termQuery("isDirectory", history.getIsDirectory() == 1));
        }

        // 可选条件7：真实名筛选（精确模糊匹配）
        if (history.getRealName() != null && !history.getRealName().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.wildcardQuery("realName", "*" + history.getRealName() + "*"));
        }

        // 2. 构建高亮配置（包含英文子字段）
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                // 文件名：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("fileName")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .field(new HighlightBuilder.Field("fileName.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                // 真实名：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("realName")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .field(new HighlightBuilder.Field("realName.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .requireFieldMatch(false); // 允许跨字段高亮

        // 3. 构建排序（默认按用户关联时间降序）
        String sortField = history.getSortField() == null ? "userFileDeleteTime" : history.getSortField();
        SortOrder sortOrder = "ASC".equalsIgnoreCase(history.getSortOrder()) ? SortOrder.ASC : SortOrder.DESC;
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withHighlightBuilder(highlightBuilder)
                .withSort(SortBuilders.fieldSort(sortField).order(sortOrder))
                .build();

        // 4. 执行查询并处理结果
        SearchHits<UserFileDocument> searchHits = esTemplate.search(searchQuery, UserFileDocument.class);
        List<Map<String, Object>> resultList = new ArrayList<>();
        searchHits.forEach(hit -> {
            UserFileDocument doc = hit.getContent();
            Map<String, Object> resultMap = new HashMap<>();
            // 基础信息

            resultMap.put("id", doc.getId());
            resultMap.put("filePath", doc.getFilePath());
            resultMap.put("isDirectory", doc.getDirectory());
            resultMap.put("fileName", doc.getFileName());
            resultMap.put("fileSize", formatFileSize(doc.getFileSize()));
            resultMap.put("fileType", doc.getFileSuffix());
            resultMap.put("fileSuffix", doc.getFileSuffix());
            resultMap.put("deleteTime", doc.getUserFileDeleteTime());
            resultMap.put("expireTime", doc.getUserFileExpireTime());
            // 高亮信息（优先子字段，再主字段）
            resultMap.put("highlightFileName", getHighlight(hit, "fileName", doc.getFileName()));
            resultList.add(resultMap);
        });
        return resultList;
    }

    public List<Map<String, Object>> getMatchContentRecycled(Long userId,FileHistory history) {
        // 1. 构建布尔查询（所有条件可选填，默认查有效文件）
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("userId", userId)) // 必选：用户隔离
                .must(QueryBuilders.termQuery("isDirectory", false)) // 必选：默认搜索文件
                .must(QueryBuilders.termQuery("isRecycled", true))
                .must(QueryBuilders.rangeQuery("userFileExpireTime").gt(new Date()));//过滤过期文件（当前时间 < 过期时间）


        // 可选条件1：关键词搜索（保留英文子字段，添加minimum_should_match）
        if (history.getKeyword() != null && !history.getKeyword().trim().isEmpty()) {
            String keyword = history.getKeyword().trim();

            // 核心：如果关键词以 . 开头，自动去掉 .（如 .txt → txt）
            if (keyword.startsWith(".")) {
                keyword = keyword.substring(1);
            }

            // 构建查询：同时匹配拆分后的词条和整体词条
            boolQuery.should(QueryBuilders.matchQuery("fileName", keyword))  // 利用 IK 分词匹配（支持中文整体）
                    .should(QueryBuilders.wildcardQuery("fileName", "*" + keyword + "*"))  // 通配符匹配（兼容特殊场景）
                    .should(QueryBuilders.wildcardQuery("realName", "*" + keyword + "*"))
                    .should(QueryBuilders.wildcardQuery("fileName.en", "*" + keyword + "*"))
                    .should(QueryBuilders.wildcardQuery("realName.en", "*" + keyword + "*"))
                    .minimumShouldMatch(1);  // 至少匹配一个条件
        }

        // 可选条件2：用户自定义文件名筛选（精确模糊匹配）
        if (history.getFileName() != null && !history.getFileName().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.wildcardQuery("fileName", "*" + history.getFileName() + "*"));
        }

        // 可选条件3：文件类型筛选（精确匹配 MIME 类型）
        if (history.getFileType() != null && !history.getFileType().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.termQuery("fileSuffix", history.getFileType()));
        }

        // 可选条件4：文件大小范围筛选
        if (history.getMinSize() != null || history.getMaxSize() != null) {
            BoolQueryBuilder sizeQuery = QueryBuilders.boolQuery();
            if (history.getMinSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").gte(history.getMinSize()));
            }
            if (history.getMaxSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").lte(history.getMaxSize()));
            }
            boolQuery.filter(sizeQuery);
        }

        // 可选条件5：时间范围筛选（修复时间格式，用时间戳查询）
        String timeField = "userFileDeleteTime"; // 默认时间字段
        if (history.getStartTime() != null || history.getEndTime() != null) {
            BoolQueryBuilder timeQuery = QueryBuilders.boolQuery();
            if (history.getStartTime() != null) {
                // 直接传入时间戳（毫秒），无需格式化
                timeQuery.must(QueryBuilders.rangeQuery(timeField).gte(history.getStartTime().getTime()));
            }
            if (history.getEndTime() != null) {
                timeQuery.must(QueryBuilders.rangeQuery(timeField).lte(history.getEndTime().getTime()));
            }
            boolQuery.filter(timeQuery);
        }

        // 可选条件6：是否目录筛选（0-文件，1-目录，未选则默认文件）
        if (history.getIsDirectory() != null) {
            boolQuery.filter(QueryBuilders.termQuery("isDirectory", history.getIsDirectory() == 1));
        }

        // 可选条件7：真实名筛选（精确模糊匹配）
        if (history.getRealName() != null && !history.getRealName().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.wildcardQuery("realName", "*" + history.getRealName() + "*"));
        }

        // 2. 构建高亮配置（包含英文子字段）
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                // 文件名：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("fileName")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .field(new HighlightBuilder.Field("fileName.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                // 真实名：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("realName")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .field(new HighlightBuilder.Field("realName.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .requireFieldMatch(false); // 允许跨字段高亮

        // 3. 构建排序（默认按用户关联时间降序）
        String sortField = history.getSortField() == null ? "userFileDeleteTime" : history.getSortField();
        SortOrder sortOrder = "ASC".equalsIgnoreCase(history.getSortOrder()) ? SortOrder.ASC : SortOrder.DESC;
        Pageable pageable = PageRequest.of(0, 10); // 第0页，每页10条（即最多返回10条）

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQuery) // 设置查询条件
                .withHighlightBuilder(highlightBuilder) // 设置高亮
                .withSort(SortBuilders.fieldSort(sortField).order(sortOrder)) // 设置排序
                .withPageable(pageable) // 用分页限制结果数量（替代size）
                .build();

        // 4. 执行查询并处理结果
        SearchHits<UserFileDocument> searchHits = esTemplate.search(searchQuery, UserFileDocument.class);
        List<Map<String, Object>> resultList = new ArrayList<>();
        searchHits.forEach(hit -> {
            UserFileDocument doc = hit.getContent();
            Map<String, Object> resultMap = new HashMap<>();
            // 仅保留：文件名（优先高亮）、文件内容（优先高亮）
            resultMap.put("fileName", getHighlight(hit, "fileName", doc.getFileName())); // 高亮文件名（前端左侧显示）
            resultMap.put("deleteTime", doc.getUserFileDeleteTime());
            resultList.add(resultMap);
        });



        return resultList;

    }

    //文件分享全局搜索
    public List<Map<String, Object>> multiConditionShareSearch(Long userId, FileHistory history) {


        // 1. 构建布尔查询（所有条件可选填，默认查有效文件）
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("userId", userId)); // 必选：用户隔离
//                .must(QueryBuilders.rangeQuery("expireTime").gt(new Date()));//过滤过期文件（当前时间 < 过期时间）

        // 可选条件1：关键词搜索（保留英文子字段，添加minimum_should_match）
        // 可选条件1：关键词搜索（优化语法和性能）
        if (history.getKeyword() != null && !history.getKeyword().trim().isEmpty()) {
            String keyword = history.getKeyword().trim();
            if (keyword.startsWith(".")) {
                keyword = keyword.substring(1);
            }

            // 构建“should”查询的子布尔查询，确保语法正确
            BoolQueryBuilder shouldQuery = QueryBuilders.boolQuery()
                    .should(QueryBuilders.matchQuery("fileName", keyword).analyzer("ik_max_word")) // 显式指定IK分词器
                    .should(QueryBuilders.wildcardQuery("fileName", "*" + keyword + "*").boost(0.5f)) // 降低通配符权重
                    .should(QueryBuilders.wildcardQuery("fileName.en", "*" + keyword + "*").boost(0.3f))
                    .minimumShouldMatch(1);

            // 将shouldQuery作为must子句，确保查询生效
            boolQuery.must(shouldQuery);
        }

        // 可选条件2：用户自定义文件名筛选（精确模糊匹配）
        if (history.getFileName() != null && !history.getFileName().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.wildcardQuery("fileName", "*" + history.getFileName() + "*"));
        }

        // 可选条件3：文件类型筛选（根据类型匹配对应后缀列表）
        if (history.getFileType() != null && !history.getFileType().trim().isEmpty()) {
            String fileType = history.getFileType().trim();
            List<String> suffixList = FILE_TYPE_SUFFIX_MAP.get(fileType);

            if (suffixList != null && !suffixList.isEmpty()) {
                // 若有后缀列表，匹配 fileSuffix 属于该列表
                boolQuery.filter(QueryBuilders.termsQuery("fileSuffix", suffixList));
            } else if ("other".equals(fileType)) {
                // 若为“其他”类型，匹配 fileSuffix 不属于所有已知后缀
                List<String> allKnownSuffixes = new ArrayList<>();
                FILE_TYPE_SUFFIX_MAP.forEach((type, suffixes) -> allKnownSuffixes.addAll(suffixes));
                boolQuery.filter(QueryBuilders.boolQuery()
                        .mustNot(QueryBuilders.termsQuery("fileSuffix", allKnownSuffixes))
                        .should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("fileSuffix")))
                        .minimumShouldMatch(1));
            }
        }

        // 可选条件4：文件大小范围筛选
        if (history.getMinSize() != null || history.getMaxSize() != null) {
            BoolQueryBuilder sizeQuery = QueryBuilders.boolQuery();
            if (history.getMinSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").gte(history.getMinSize()));
            }
            if (history.getMaxSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").lte(history.getMaxSize()));
            }
            boolQuery.filter(sizeQuery);
        }

        // 可选条件5：时间范围筛选（修复时间格式，用时间戳查询）
        String timeField = "createTime"; // 默认时间字段
        if (history.getStartTime() != null || history.getEndTime() != null) {
            BoolQueryBuilder timeQuery = QueryBuilders.boolQuery();
            if (history.getStartTime() != null) {
                // 直接传入时间戳（毫秒），无需格式化
                timeQuery.must(QueryBuilders.rangeQuery(timeField).gte(history.getStartTime().getTime()));
            }
            if (history.getEndTime() != null) {
                timeQuery.must(QueryBuilders.rangeQuery(timeField).lte(history.getEndTime().getTime()));
            }
            boolQuery.filter(timeQuery);
        }



        // 2. 构建高亮配置（包含英文子字段）
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                // 文件名：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("fileName")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .field(new HighlightBuilder.Field("fileName.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .requireFieldMatch(false); // 允许跨字段高亮

        // 3. 构建排序（默认按用户关联时间降序）
        String sortField = history.getSortField() == null ? "createTime" : history.getSortField();
        SortOrder sortOrder = "ASC".equalsIgnoreCase(history.getSortOrder()) ? SortOrder.ASC : SortOrder.DESC;
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withHighlightBuilder(highlightBuilder)
                .withSort(SortBuilders.fieldSort(sortField).order(sortOrder))
                .build();

        // 4. 执行查询并处理结果
        SearchHits<FileShareDocument> searchHits = esTemplate.search(searchQuery, FileShareDocument.class);
        List<Map<String, Object>> resultList = new ArrayList<>();
        searchHits.forEach(hit -> {
            FileShareDocument doc = hit.getContent();
            Map<String, Object> resultMap = new HashMap<>();
            // 基础信息

            resultMap.put("id", doc.getId());
            resultMap.put("fileName", doc.getFileName());
            resultMap.put("fileSize", formatFileSize(doc.getFileSize()));
            resultMap.put("fileType", doc.getFileSuffix());
            resultMap.put("fileSuffix", doc.getFileSuffix());
            resultMap.put("createTime", doc.getCreateTime());
            resultMap.put("expireTime", doc.getExpireTime());
            // 高亮信息（优先子字段，再主字段）
            resultMap.put("highlightFileName", getHighlight2(hit, "fileName", doc.getFileName()));
            resultList.add(resultMap);
        });
        return resultList;
    }

    public List<Map<String, Object>> getMatchContentShare(Long userId,FileHistory history) {
        // 1. 构建布尔查询（所有条件可选填，默认查有效文件）
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("userId", userId)); // 必选：用户隔离
//                .must(QueryBuilders.rangeQuery("expireTime").gt(new Date()));//过滤过期文件（当前时间 < 过期时间）

        // 可选条件1：关键词搜索（保留英文子字段，添加minimum_should_match）
        if (history.getKeyword() != null && !history.getKeyword().trim().isEmpty()) {
            String keyword = history.getKeyword().trim();

            // 核心：如果关键词以 . 开头，自动去掉 .（如 .txt → txt）
            if (keyword.startsWith(".")) {
                keyword = keyword.substring(1);
            }

            // 构建查询：同时匹配拆分后的词条和整体词条
            boolQuery.should(QueryBuilders.matchQuery("fileName", keyword))  // 利用 IK 分词匹配（支持中文整体）
                    .should(QueryBuilders.wildcardQuery("fileName", "*" + keyword + "*"))  // 通配符匹配（兼容特殊场景）
                    .should(QueryBuilders.wildcardQuery("fileName.en", "*" + keyword + "*"))
                    .minimumShouldMatch(1);  // 至少匹配一个条件
        }

        // 可选条件2：用户自定义文件名筛选（精确模糊匹配）
        if (history.getFileName() != null && !history.getFileName().trim().isEmpty()) {
            boolQuery.filter(QueryBuilders.wildcardQuery("fileName", "*" + history.getFileName() + "*"));
        }

        // 可选条件3：文件类型筛选（根据类型匹配对应后缀列表）
        if (history.getFileType() != null && !history.getFileType().trim().isEmpty()) {
            String fileType = history.getFileType().trim();
            List<String> suffixList = FILE_TYPE_SUFFIX_MAP.get(fileType);

            if (suffixList != null && !suffixList.isEmpty()) {
                // 若有后缀列表，匹配 fileSuffix 属于该列表
                boolQuery.filter(QueryBuilders.termsQuery("fileSuffix", suffixList));
            } else if ("other".equals(fileType)) {
                // 若为“其他”类型，匹配 fileSuffix 不属于所有已知后缀
                List<String> allKnownSuffixes = new ArrayList<>();
                FILE_TYPE_SUFFIX_MAP.forEach((type, suffixes) -> allKnownSuffixes.addAll(suffixes));
                boolQuery.filter(QueryBuilders.boolQuery()
                        .mustNot(QueryBuilders.termsQuery("fileSuffix", allKnownSuffixes))
                        .should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("fileSuffix")))
                        .minimumShouldMatch(1));
            }
        }

        // 可选条件4：文件大小范围筛选
        if (history.getMinSize() != null || history.getMaxSize() != null) {
            BoolQueryBuilder sizeQuery = QueryBuilders.boolQuery();
            if (history.getMinSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").gte(history.getMinSize()));
            }
            if (history.getMaxSize() != null) {
                sizeQuery.must(QueryBuilders.rangeQuery("fileSize").lte(history.getMaxSize()));
            }
            boolQuery.filter(sizeQuery);
        }

        // 可选条件5：时间范围筛选（修复时间格式，用时间戳查询）
        String timeField = "createTime"; // 默认时间字段
        if (history.getStartTime() != null || history.getEndTime() != null) {
            BoolQueryBuilder timeQuery = QueryBuilders.boolQuery();
            if (history.getStartTime() != null) {
                // 直接传入时间戳（毫秒），无需格式化
                timeQuery.must(QueryBuilders.rangeQuery(timeField).gte(history.getStartTime().getTime()));
            }
            if (history.getEndTime() != null) {
                timeQuery.must(QueryBuilders.rangeQuery(timeField).lte(history.getEndTime().getTime()));
            }
            boolQuery.filter(timeQuery);
        }



        // 2. 构建高亮配置（包含英文子字段）
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                // 文件名：主字段 + 英文子字段
                .field(new HighlightBuilder.Field("fileName")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .field(new HighlightBuilder.Field("fileName.en")
                        .preTags("<span class='highlight-keyword'>")
                        .postTags("</span>")
                        .fragmentSize(100))
                .requireFieldMatch(false); // 允许跨字段高亮

        // 3. 构建排序（默认按用户关联时间降序）
        String sortField = history.getSortField() == null ? "createTime" : history.getSortField();
        SortOrder sortOrder = "ASC".equalsIgnoreCase(history.getSortOrder()) ? SortOrder.ASC : SortOrder.DESC;
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withHighlightBuilder(highlightBuilder)
                .withSort(SortBuilders.fieldSort(sortField).order(sortOrder))
                .build();

        // 4. 执行查询并处理结果
        SearchHits<FileShareDocument> searchHits = esTemplate.search(searchQuery, FileShareDocument.class);
        List<Map<String, Object>> resultList = new ArrayList<>();
        searchHits.forEach(hit -> {
            FileShareDocument doc = hit.getContent();
            Map<String, Object> resultMap = new HashMap<>();
            // 基础信息
            resultMap.put("createTime", doc.getCreateTime());
            // 高亮信息（优先子字段，再主字段）
            resultMap.put("fileName", getHighlight2(hit, "fileName", doc.getFileName()));
            resultList.add(resultMap);
        });
        return resultList;

    }


}